﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text.RegularExpressions;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;

namespace Sharp.Portal.Mvc.Route
{
    public class DomainRoute : System.Web.Routing.Route
    {
        public DomainRoute(string url, RouteValueDictionary defaults)
            : base(url, defaults, new MvcRouteHandler())
        {
        }

        public DomainRoute(string url, RouteValueDictionary defaults, IRouteHandler routeHandler)
            : base(url, defaults, routeHandler)
        {
        }

        public DomainRoute(string url, object defaults)
            : base(url, new RouteValueDictionary(defaults), new MvcRouteHandler())
        {
        }

        public DomainRoute(string url, object defaults, object constraints)
            : base(url, new RouteValueDictionary(defaults), new RouteValueDictionary(constraints), new MvcRouteHandler()
                )
        {
        }

        public DomainRoute(string url, object defaults, IRouteHandler routeHandler)
            : base(url, new RouteValueDictionary(defaults), routeHandler)
        {
        }

        public DomainRoute(string url, RouteValueDictionary defaults, RouteValueDictionary constraints,
            RouteValueDictionary dataTokens, IRouteHandler routeHandler) : base(url, defaults, constraints,
                dataTokens, routeHandler)
        {
        }

        /// <summary>
        /// Area数据字典缓存
        /// </summary>
        private static readonly Dictionary<string, string[]> AreaDic = new Dictionary<string, string[]>();

        static DomainRoute()
        {
            FillDomainRouteInfo();
        }

        public static void FillDomainRouteInfo()
        {
            var filepath = Assembly.GetExecutingAssembly().CodeBase.Replace("file:///", "");
            var files = Directory.GetFiles(Path.GetDirectoryName(filepath), "*.dll").ToList();

            files.ForEach(file =>
            {
                if (Platform.ThirdpartyDlls.Any(i => file.StartsWith(i, StringComparison.CurrentCultureIgnoreCase)))
                {
                    return;
                }
                byte[] fileData = File.ReadAllBytes(file);
                var assembly = Assembly.Load(fileData);
                var a = assembly.CustomAttributes.Any(x => x.AttributeType == typeof(AssemblyMvcAttribute));
                if (a)
                {
                    var names = assembly.GetTypes()
                        .Where(x => x.GetInterface(nameof(IController)) != null)
                        .Select(x => x.Namespace).GroupBy(x => x).Select(group => new { group.Key }).ToList();
                    var regex = new Regex(@"Areas\.(.*?)\.");

                    names.ForEach(x =>
                    {
                        if (AreaDic.Keys.All(key => key != regex.Match(x.Key).Groups[1].Value))
                        {
                            AreaDic.Add(regex.Match(x.Key).Groups[1].Value, new[] { x.Key });
                        }
                    });
                }

            });
        }

        public override RouteData GetRouteData(HttpContextBase httpContext)
        {
            var routeData = base.GetRouteData(httpContext);
            if (routeData == null)
            {
                return null;
            }

            if (routeData.DataTokens.ContainsKey("area")) return routeData;

            string requestHost = httpContext.Request.Headers["host"];
            var simRoute = DomainRouteConfig.GetSaasRouteTarget(requestHost);

            if (simRoute == null)
            {
#if DEBUG

                routeData.DataTokens["area"] = "Platform";
#endif
                return routeData;
            }
            routeData.Values["area"] = simRoute.Area;

            try
            {
                routeData.DataTokens["Namespaces"] = AreaDic[simRoute.Area];
            }
            catch (Exception ex)
            {
                var sb = new System.Text.StringBuilder();
                sb.AppendFormat("No，GetRouteData又出错了，AreaDic 有数据{0}条。", AreaDic.Count);
                foreach (var item in AreaDic)
                {
                    sb.AppendLine(item.Key + ":" + item.Value);
                }
                sb.AppendLine("<br />");
                sb.AppendLine(ex.Message);
                throw new System.Exception(sb.ToString());
            }

            routeData.DataTokens["area"] = simRoute.Area;

            return routeData;
        }


        public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
        {
            var virtualPathData = base.GetVirtualPath(requestContext, values);

            if (virtualPathData != null && virtualPathData.DataTokens.TryGetValue("area", out var area))
            {
                virtualPathData.VirtualPath = virtualPathData.VirtualPath.Remove(0, area.ToString().Length + 1);
            }

            return virtualPathData;
        }
    }
}